package com.woniu.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.woniu.config.ContainerCache;
import com.woniu.entity.AllUser;
import com.woniu.entity.CtfContainer;
import com.woniu.entity.CtfRange;
import com.woniu.entity.PageBean;
import com.woniu.entity.dto.ContainerCreationResponse;
import com.woniu.entity.vo.ContainerVo;
import com.woniu.mapper.CtfRangeMapper;
import com.woniu.service.CtfContainerService;
import com.woniu.mapper.CtfContainerMapper;
import com.woniu.service.CtfRangeService;
import com.woniu.utils.DockerUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author nanqiao
 * @description 针对表【ctf_container】的数据库操作Service实现
 * @createDate 2025-06-09 17:11:49
 */
@Service
public class CtfContainerServiceImpl extends ServiceImpl<CtfContainerMapper, CtfContainer>
        implements CtfContainerService {
    @Autowired
    private DockerUtils dockerUtil;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private CtfContainerMapper ctfContainerMapper;
    @Autowired
    private CtfRangeMapper ctfRangeMapper;
    @Autowired
    private ContainerCache containerCache;
    /**
     * @param imageId       镜像id或者名字，注意是镜像名字+tag的名字
     * @param containerName 所创建容器的名字，容器名字不能一样
     * @param containerPort 镜像文件里面所暴露的端口如测试文件book(80),加入80，后续试试多文件传入多个暴露端口
     * @param flagValue     存入容器temp或者root目录的密钥flag值，一个有权限，一个无权就可以访问
     * @return 返回值应该返回容器密钥存放地址，访问地址ip:80,后续修改
     * @throws IOException
     * @author hq
     */
    @Override
    public void createContainer(String imageId, String containerName, int containerPort, String flagValue)
            throws IOException {
        // 1. 准备容器实体
        CtfContainer container = new CtfContainer();
        container.setFlagValue(DigestUtil.md5Hex(flagValue));
        container.setUserId(1);
        container.setRangeId(imageId);
        //2、直接传入值创建容器
        try {
//            container = dockerUtil.createContainerWithFlag(imageId, containerName, containerPort, flagValue);
            // 5. 设置容器信息
            container.setSocket(String.valueOf(containerPort));
            // 6. 存储flag到Redis (10分钟有效期)
            redisTemplate.opsForValue().set(
                    "flag:" + container.getContainerId(),
                    container.getFlagValue(),
                    10,
                    TimeUnit.MINUTES);
            // 7. 保存到数据库
            ctfContainerMapper.insertContainer(container);
        } catch (Exception e){
           throw new RuntimeException(e);
        }
    }
    /**
     * @author hq
     * @param containerId 可以传入容器id或者容器名字
     * @return 具体返回值，按需求修改
     */
    @Override
    public void startContainer(String containerId) {
        dockerUtil.startContainer(containerId);
    }
    /**
     * @author hq
     * @param containerIdOrName 可以传入容器id或者容器名字
     *  @return 具体返回值，按需求修改
     */
    @Override
    public void stopContainer(String containerIdOrName) {
        dockerUtil.stopContainer(containerIdOrName);
    }

    @Override
    public void createStartContainer(String imageId, String containerName, int containerPort, String flagValue) {
        // 1. 准备容器实体
        CtfContainer container = new CtfContainer();
        container.setFlagValue(DigestUtil.md5Hex(flagValue));
        container.setUserId(1);
        container.setRangeId(imageId);
        //2、直接传入值创建容器
        try {
//            container = dockerUtil.createAndStartContainerWithFlag(imageId, containerName, containerPort, flagValue);
            // 6. 存储flag到Redis (10分钟有效期)
            redisTemplate.opsForValue().set(
                    "flag:" + container.getContainerId(),
                    container.getFlagValue(),
                    10,
                    TimeUnit.MINUTES);
            // 7. 保存到数据库
            ctfContainerMapper.insertContainer(container);
        } catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    @Override
    public PageBean<CtfContainer> selectPage(Integer pageNum, Integer pageSize, CtfContainer container) {
        //创建PageBean对象
        PageBean<CtfContainer> pg = new PageBean<>();
        //开启分页查询 PageHelper
        PageHelper.startPage(pageNum, pageSize);
        List<CtfContainer> containers = ctfContainerMapper.selectPageList(container);
        PageInfo<CtfContainer> pageInfo = new PageInfo<>(containers);
        pg.setTotal(pageInfo.getTotal());
        pg.setList(pageInfo.getList());
        return pg;
    }

    @Override
    public ContainerVo startContainerByIdOrName(String rangeId, String rangeName) {
        String flag = RandomUtil.randomString(6);
//        String flagValue = DigestUtil.md5Hex(flag);
        //从range表里面获取flagPath
//        String flagPath = ctfRangeMapper.selectFlagPath(rangeId);
        CtfContainer container = new CtfContainer();
        container.setFlagValue(flag);
        container.setUserId(1);
        CtfRange ctfRange = null;
        String containerName = null;
        int containerPort = 0;
        try {
            ctfRange = ctfRangeMapper.selectById(rangeId);
            container.setRangeId(rangeId);
            //给imageId拼接上sha256:
//            rangeId = "sha256:" + rangeId;
            containerPort = Integer.parseInt(ctfRange.getExposePort());
            int randomNumber = (int) (Math.random() * 90) + 10; // 生成 10~99 的随机整数
            containerName = ctfRange.getRangeName().replace(":latest", "") + "_" + randomNumber;
            String flagPath = ctfRange.getFlagPath();
            container = dockerUtil.createAndStartContainerWithFlag(rangeId,flagPath, containerName, containerPort, flag);
        } catch (Exception e) {
            if (rangeName != null && !rangeName.isEmpty()) {
                //给rangeName拼接一个：latest
                rangeName += ":latest";
                ctfRange = ctfRangeMapper.selectByRangeName(rangeName);
                container.setRangeId(ctfRange.getRangeId());
                containerPort = Integer.parseInt(ctfRange.getExposePort());
                int randomNumber = (int) (Math.random() * 90) + 10; // 生成 10~99 的随机整数
                containerName = ctfRange.getRangeName().replace(":latest", "") + "_" + randomNumber;
                String flagPath = ctfRange.getFlagPath();
                container = dockerUtil.createAndStartContainerWithFlag(rangeName, flagPath,containerName, containerPort, flag);
            } else {
                throw new RuntimeException("启动失败");
            }
        }
        // 添加到缓存
        containerCache.addContainer(container.getContainerId());
        //从score_difficulty表里面获取perfect_time的两倍设置倒计时
        int timeoutSeconds = ctfRangeMapper.selectTimeout(ctfRange.getDifficultyId())*60*2;
        // 存储flag到Redis
        redisTemplate.opsForValue().set(
                "flag:" + container.getContainerId(),
                container.getFlagValue(),
                timeoutSeconds,
                TimeUnit.SECONDS);
        // 构造响应
        String startTime = LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME);
        ctfContainerMapper.insertContainer(container);
        return new ContainerVo(container.getContainerId(),container.getSocket(), startTime, timeoutSeconds);
    }

    @Override
    public void updateContainerUpdateTime(String containerId, Date date) {
        //获取当前用户信息
//        AllUser user = (AllUser) StpUtil.getSession().get("user");
//        ctfContainerMapper.updateContainerUpdateTime(containerId, date, user.getUserName());
        ctfContainerMapper.updateContainerUpdateTime(containerId, date);

    }

    @Override
    public void updateFlagMatchAndTime(String containerId) {
        CtfContainer container = ctfContainerMapper.selectById(containerId);
        container.setIsFlagMatch(1); // 设置 flag 匹配标志
        container.setUpdateTime(new Date()); // 更新修改时间
        ctfContainerMapper.updateById(container);
    }
}




